package com.gjy.encryption.asymmetric;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;

/**
 * RSA加解密算法
 *
 * @author 宫静雨
 * @version 1.0
 * @since 2022-11-05 11:42:25
 */
public class RSACoder {

    public RSACoder() {
        initKey();
    }

    // 非对称秘钥算法
    private static final String KEY_ALGORITHM = "RSA";
    // 公钥
    private static final String PUBLIC_KEY = "RASPublicKey";
    // 私钥
    private static final String PRIVATE_KEY = "RASPrivateKey";
    // RSA秘钥长度，默认1024位，范围512-65536之间，64的倍数
    private static final Integer KEY_SIZE = 512;
    private static final HashMap<String, Key> map = new HashMap<>(4);

    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @return 解密数据
     * @throws Exception 异常
     */
    public byte[] decryptByPublicKey(byte[] data) throws Exception {
        // 取得私钥
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(getPublicKey());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 生成私钥
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        // 数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @return 加密数据
     * @throws Exception 异常
     */
    public byte[] encryptByPublicKey(byte[] data) throws Exception {
        // 取得私钥
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(getPublicKey());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 生成私钥
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        // 数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥解密
     *
     * @param data 待解密数据
     * @return 解密数据
     * @throws Exception 异常
     */
    public byte[] decryptByPrivateKey(byte[] data) throws Exception {
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(getPrivateKey());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        // 数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥加密
     *
     * @param data 待加密数据
     * @return 加密数据
     * @throws Exception 异常
     */
    public byte[] encryptByPrivateKey(byte[] data) throws Exception {
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(getPrivateKey());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        // 数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 获得公钥
     *
     * @return 私钥
     */
    private byte[] getPublicKey() {
        Key key = map.get(PUBLIC_KEY);
        return key.getEncoded();
    }

    /**
     * 获得私钥
     *
     * @return 私钥
     */
    private byte[] getPrivateKey() {
        Key key = map.get(PRIVATE_KEY);
        return key.getEncoded();
    }

    /**
     * 初始化密钥对
     */
    private void initKey() {
        try {
            // 实例化秘钥对生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(KEY_SIZE);
            // 生成秘钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            map.put(PUBLIC_KEY, publicKey);
            map.put(PRIVATE_KEY, privateKey);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}
